using System;
using System.Collections;
using System.IO;
using Game.Framework.FState;
using Game.Framework.Utils;
using UnityEngine;
using UnityEngine.U2D;
using YooAsset;

namespace Game.Framework
{
    public class YooAssetManager : MonoSingleton<YooAssetManager>
    {
        public ResourcePackage Package { get; private set; }
        
        // 是否使用低清图集
        private bool m_useSdAtlas = false;

        private StateMachine<StateYooAssetBase> _stateMachine;

        public IEnumerator Initialized()
        {
            _stateMachine = new StateMachine<StateYooAssetBase>();
            YooAssets.Initialize();
            
            SpriteAtlasManager.atlasRequested += SpriteAtlasManagerOnAtlasRequested;
            
            string name = AssetConfig.Instance.PackageName;
            Package = YooAssets.TryGetPackage(name);
            if (Package == null)
                Package = YooAssets.CreatePackage(name);

            YooAssets.SetDefaultPackage(Package);
            
            // 编辑器下的模拟模式
            InitializationOperation initializationOperation = null;
            if (AssetConfig.Instance.RunMode == EPlayMode.EditorSimulateMode)
            {
                var createParameters = new EditorSimulateModeParameters();
                string buildPipeline = EDefaultBuildPipeline.BuiltinBuildPipeline.ToString();
                var simulateBuildResult = EditorSimulateModeHelper.SimulateBuild(buildPipeline, name);
                createParameters.EditorFileSystemParameters =
                    FileSystemParameters.CreateDefaultEditorFileSystemParameters(simulateBuildResult);
                initializationOperation = Package.InitializeAsync(createParameters);
            }

            // 单机运行模式
            if (AssetConfig.Instance.RunMode == EPlayMode.OfflinePlayMode)
            {
                var buildinFileSystem = FileSystemParameters.CreateDefaultBuildinFileSystemParameters();
                var initParameters = new OfflinePlayModeParameters();
                initParameters.BuildinFileSystemParameters = buildinFileSystem;
                initializationOperation = Package.InitializeAsync(initParameters);
            }

            // 联机运行模式
            if (AssetConfig.Instance.RunMode == EPlayMode.HostPlayMode)
            {
                var path = Path.Combine(PathUtils.BaseAssetDownLoadPath, AssetConfig.Instance.AndroidVersion);
                string defaultHostServer = path;
                string fallbackHostServer = path;
                IRemoteServices remoteServices = new RemoteServices(defaultHostServer, fallbackHostServer);
                var createParameters = new HostPlayModeParameters();
                createParameters.BuildinFileSystemParameters =
                    FileSystemParameters.CreateDefaultBuildinFileSystemParameters();
                createParameters.CacheFileSystemParameters =
                    FileSystemParameters.CreateDefaultCacheFileSystemParameters(remoteServices);
                initializationOperation = Package.InitializeAsync(createParameters);
            }
            
            // WebGL运行模式
            if (AssetConfig.Instance.RunMode == EPlayMode.WebPlayMode)
            {
                var createParameters = new WebPlayModeParameters();
                createParameters.WebFileSystemParameters = FileSystemParameters.CreateDefaultWebFileSystemParameters();
                initializationOperation = Package.InitializeAsync(createParameters);
            }

            yield return initializationOperation;
            if (initializationOperation.Status != EOperationStatus.Succeed)
            {
                var error = initializationOperation.Error;
                EventBus.Send(new EventInitializationOperationFailed(error));
            }
            else
            {
                _stateMachine.SetState<StateYooAssetUpdatePackageVersion>(null);
            }
        }
        
        private string GetExistingSpriteAtlasPath(string atlasName)
        {
            AtlasPathNode atlasPathNode = AtlasConfigController.Instance.GetAtlasPath(atlasName);
            if (atlasPathNode == null)
            {
                LogUtil.LogError("SpriteAtlas Path Error:" + atlasName);
                return null;
            }

            //编辑器模式使用高清图集
            if (AssetConfig.Instance.RunMode == EPlayMode.EditorSimulateMode)
            {
                return atlasPathNode.HdPath;
            }

            if (!m_useSdAtlas) // 要求使用高清
            {
                return atlasPathNode.HdPath;
            }
            
            return atlasPathNode.SdPath;// 返回低清图集
        }

        public SpriteAtlas LoadSpriteAtlas(string atlasName)
        {
            SpriteAtlas atlas = null;
            string _atlasPath = GetExistingSpriteAtlasPath(atlasName);
            if (string.IsNullOrEmpty(_atlasPath))
            {
                LogUtil.LogError($"Erro =====> 没有从现有的 AtlasConfigController 里找到图集: {atlasName}");
                return atlas;
            }
            
            var handle = Package.LoadAssetSync<SpriteAtlas>(_atlasPath);
            atlas = handle.AssetObject as SpriteAtlas;
            return atlas;
        }

        private void OnDestroy()
        {
            SpriteAtlasManager.atlasRequested -= SpriteAtlasManagerOnAtlasRequested;
        }

        public Sprite GetSprite(string atlasName, string spriteName)
        {
            try
            {
                SpriteAtlas sa = LoadSpriteAtlas(atlasName);
                if (sa == null)
                {
                    LogUtil.LogError("sprite load error:" + atlasName + ":" + spriteName);
                    return null;
                }

                var sprite = sa.GetSprite(spriteName);
                if (sprite == null)
                {
                    LogUtil.LogError($"sprite load error, atlas : {atlasName}, sprite name : {spriteName}");
                }

                return sprite;
            }
            catch (Exception e)
            {
                LogUtil.LogError(e);
            }
            return null;
        }
        
        private void SpriteAtlasManagerOnAtlasRequested(string atlasName, Action<SpriteAtlas> register)
        {
            LogUtil.Log("Atlas requested : {0}",atlasName);
            SpriteAtlas sa = LoadSpriteAtlas(atlasName);
            if (sa != null)
            {
                LogUtil.Log("Atlas loaded : {0}",atlasName);
            }
            register(sa);
        }
    }
}


